local Color = require "color"
local ffi = require "ffi"

local BorderRadius = require "border_radius"
require "rect"
require "vec4"

ffi.cdef [[
    typedef struct
    {
        vec4_t color;
        border_radius_t border_radius;
    } renderable_rect_t;

    typedef struct
    {
        const char* text;
        vec4_t color;
        float font_size;
    } renderable_text_t;

    uint64_t division_ffi_create_drawable_rect(void* state, void* render_manager);
    uint64_t division_ffi_create_drawable_text(void* state, void* render_manager);
    void division_ffi_destroy_entity(void* state, uint64_t entity_id);

    void division_ffi_set_RenderBounds(
        void* state, uint64_t entity_id, rect_t bounds);
    void division_ffi_set_RenderableRect(
        void* state, uint64_t entity_id, renderable_rect_t renderable_rect);
    void division_ffi_set_c_renderable_text(
        void* state, uint64_t entity_id, renderable_text_t renderable_text);

    vec2_t division_ffi_get_screen_size(void* state);
    vec2_t division_ffi_get_mouse_position(void* state);
]]

local create_rect = ffi.C.division_ffi_create_drawable_rect
local create_text = ffi.C.division_ffi_create_drawable_text
local destroy_entity = ffi.C.division_ffi_destroy_entity
local set_bounds = ffi.C.division_ffi_set_RenderBounds
local set_renderable_rect = ffi.C.division_ffi_set_RenderableRect
local set_renderable_text = ffi.C.division_ffi_set_c_renderable_text
local get_screen_size = ffi.C.division_ffi_get_screen_size
local get_mouse_position = ffi.C.division_ffi_get_mouse_position

local renderable_rect_t = ffi.typeof("renderable_rect_t")
local renderable_text_t = ffi.typeof("renderable_text_t")

---@class division
local division = {}

---@private
division.__state__ = __ENGINE_STATE__

---@private
division.__render_manager__ = __RENDER_MANAGER__

---Draw rect with render manager
---@param bounds rect?
---@param color vec4?
---@param border_radius border_radius?
---@return number # drawable ecs entity id
function division:create_drawable_rect(bounds, color, border_radius)
    local entity_id = create_rect(self.__state__, self.__render_manager__)

    if bounds or color or border_radius then
        self:set_drawable_rect(entity_id, bounds, color, border_radius)
    end

    return entity_id
end

---Draw text with render manager
---@param text string?
---@param bounds rect?
---@param color vec4?
---@param font_size number?
---@return number # drawable ecs entity id
function division:create_drawable_text(text, bounds, color, font_size)
    local entity_id = create_text(self.__state__, self.__render_manager__)

    if text or bounds or color or font_size then
        self:set_drawable_text(entity_id, text, bounds, color, font_size)
    end

    return entity_id
end

---Set rect parameters
---@param entity_id number
---@param bounds rect?
---@param color vec4?
---@param border_radius border_radius?
function division:set_drawable_rect(entity_id, bounds, color, border_radius)
    set_bounds(self.__state__, entity_id, bounds)
    set_renderable_rect(
        self.__state__,
        entity_id,
        ffi.new(
            renderable_rect_t,
            {
                color = color or Color.BLACK,
                border_radius = border_radius or BorderRadius.all(0)
            }
        )
    )
end

---Set drawable text parameters
---@param entity_id number
---@param text string?
---@param bounds rect?
---@param color vec4?
---@param font_size number?
function division:set_drawable_text(entity_id, text, bounds, color, font_size)
    set_bounds(self.__state__, entity_id, bounds)
    set_renderable_text(
        self.__state__,
        entity_id,
        ffi.new(
            renderable_text_t,
            {
                text = text or "",
                color = color or Color.BLACK,
                font_size = font_size or 16
            }
        )
    )
end

function division:screen_size()
    return get_screen_size(self.__state__)
end

function division:mouse_position()
    return get_mouse_position(self.__state__)
end

--Destroy ecs entity
---@param entity_id number
function division:destroy_entity(entity_id)
    destroy_entity(self.__state__, entity_id)
end

---@private
division.__destroy_listeners__ = {}

---@private
division.__update_listeners__ = {}

---@private
function division:__on_destroy__()
    for _, listener in ipairs(self.__destroy_listeners__) do
        listener()
    end
end

---@private
function division:__on_update__()
    for _, listener in ipairs(self.__update_listeners__) do
        listener()
    end
end

---@param listener function
function division:add_destroy_listener(listener)
    table.insert(self.__destroy_listeners__, listener)
end

---@param listener function
function division:add_update_listener(listener)
    table.insert(self.__update_listeners__, listener)
end

__ON_DESTROY__ = function()
    division:__on_destroy__()
end

__ON_UPDATE__ = function()
    division:__on_update__()
end

return division
